#include "Prepare.hpp"

using namespace BFT::order::messages;

Commit::Commit(uint32_t _view, uint32_t _seq, boost::shared_ptr<BFT::messages::HistoryDigest> _pphash, uint32_t _sendingReplica)
	: MacArrayMessage::MacArrayMessage((uint16_t)COMMIT, computeSize(_pphash), _sendingReplica, BFT::Parameters::getOrderCount())
{
	viewNo = _view;
	seqNo = _seq;
	ppHash = _pphash;
	
	int offset = getOffset();
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	//write the view number
	*(uint32_t*)(bytes.get()+offset) = htonl(viewNo);
	offset += VIEW_NUMBER_SIZE;

	//write the sequence number
	*(uint32_t*)(bytes.get()+offset) = htonl(seqNo);
	offset += SEQUENCE_NUMBER_SIZE;
	
	//write the history
	int temp_history_size = BFT::messages::HistoryDigest::size();
	boost::shared_ptr<char> temp_history = ppHash.get()->getBytes();
	memcpy( (void *)(bytes.get()+offset) , (const void *)(temp_history.get()) , temp_history_size);
	offset += temp_history_size;
}

Commit::Commit(boost::shared_ptr<Prepare> _p, uint32_t _sendingReplica)
{
	Commit(_p.get()->getView(),_p.get()->getSeqNo(), _p.get()->getPrePrepareHash(), _sendingReplica);
}

Commit::Commit(boost::shared_ptr<char> _bytes, int _bytes_size)
	: MacArrayMessage::MacArrayMessage(_bytes, _bytes_size)
{
	if (getTag() != COMMIT)
	{
		fprintf(stderr,"trying to build PREPARE from invalid bytes. expected tag (prepare: %d, actual tag: %d)\n",PREPARE, getTag());
		exit(81);
	}
	
	int offset = getOffset();
	
	//read the view number
	viewNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += VIEW_NUMBER_SIZE;
	
	//read the sequence number
	seqNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += SEQUENCE_NUMBER_SIZE;
	
	//read the preprepare hash
	int hash_size = BFT::messages::HistoryDigest::size();
	boost::shared_ptr<char> temp_history_bytes ((char*)malloc(hash_size), free);
	memcpy( (void * )temp_history_bytes.get() , (const void*)(_bytes.get()+offset) , hash_size);
	offset += hash_size;
	ppHash = BFT::messages::HistoryDigest::fromBytes(temp_history_bytes, hash_size);
	
	if((unsigned int)offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr, "trying to create prepare from invalid bytes\n");
		exit(82);
	}
}

bool Commit::equals(boost::shared_ptr<Commit> _other_c)
{
	bool equal = MacArrayMessage::equals(_other_c) && viewNo == _other_c.get()->getView() &&
		     seqNo == _other_c.get()->getSeqNo() && ppHash.get()->equals( _other_c.get()->getPrePrepareHash() );
	return equal;	     	
}

/*
bool Prepare::matches(boost::shared_ptr<BFT::messages::VerifiedMessageBase> _other_vmb)
{
	bool match = false;
	if (_other_vmb.use_count() != 0 && _other_vmb.get()->getTag() == PREPARE )
	{
		boost::shared_ptr<Prepare> _other_p = boost::dynamic_pointer_cast<Prepare>(_other_vmb);
		match = viewNo == _other_p.get()->getView() &&  
		        seqNo == _other_p.get()->getSeqNo() && 
		        ppHash.get()->equals( _other_p.get()->getPrePrepareHash());
	}
	else
	{
		if (_other_vmb.use_count() != 0 && _other_vmb.get()->getTag() == COMMIT)
		{
			boost::shared_ptr<Commit> other_c = boost::dynamic_pointer_cast<Commit>(_other_vmb);
			match = viewNo == other_c.get()->getView() &&  
			        seqNo == other_c.get()->getSeqNo() && 
			        ppHash.get()->equals( other_c.get()->getPrePrepareHash());
		}
	}	
	return match;
}
*/
void Commit::printInfo()
{
	fprintf(stdout,"Commit information:\n");
	fprintf(stdout,"viewNo: %d, seqNo: %d, sender: %d\n",viewNo, seqNo, getSender());
}
